package guggaTests.tasks.containers
{
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import flexunit.framework.TestCase;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.tasks.ExecuteAsyncMethodTask;
	import gugga.tasks.FictiveTask;
	import gugga.tasks.FrameWaitingTask;
	import gugga.tasks.IProgressiveTask;
	import gugga.tasks.ITask;
	import gugga.tasks.WaitingTask;
	import gugga.tasks.containers.ProgressMonitor;
	import gugga.tasks.containers.TaskSequence;
	import gugga.tasks.events.ProgressiveTaskEvent;
	import gugga.tasks.events.TaskEvent;
	import gugga.utils.DoLaterUtil;

	public class ProgressMonitorTest extends TestCase
	{
		private var mProgressMonitor : ProgressMonitor;
		private var mIsProgressMonitorProgress : Boolean;
		private var mProgress : Number;
		
		public function ProgressMonitorTest(methodName:String=null)
		{
			super(methodName);
		}
		
		public override function setUp() : void
		{
			mProgressMonitor = new ProgressMonitor();
			mProgress = 0;
			mIsProgressMonitorProgress = false;
		}
		
		public function testConstructor() : void
		{
			assertNotNull("ProgressMonitor should not be null after creation", mProgressMonitor);
			assertNotUndefined("ProgressMonitor should not be undefined after creation", mProgressMonitor);
		}
		
		public function testAddAndRemoveItem() : void
		{
			var fictiveTask1 : FictiveTask = new FictiveTask();
			var fictiveTask2 : FictiveTask = new FictiveTask();
			var fictiveTask3 : FictiveTask = new FictiveTask();
			
			mProgressMonitor.addItem(fictiveTask1);			
			mProgressMonitor.addItem(fictiveTask2);
			mProgressMonitor.addItem(fictiveTask3);
			
			mProgressMonitor.removeItem(fictiveTask2);
			mProgressMonitor.removeItem(fictiveTask3);
			
			assertEquals("getProgress() should return 0", mProgressMonitor.getProgress(), 0);
			
			mProgressMonitor.addEventListener(ProgressiveTaskEvent.PROGRESS, onProgressMonitorProgress);
			mProgressMonitor.addEventListener(TaskEvent.COMPLETED, addAsync(assertProgressMonitorCompleted, 400));
			
			mProgressMonitor.start();
			
			fictiveTask1.start();			
		}
		
		private function onProgressMonitorProgress(aEvent : ProgressiveTaskEvent) : void
		{
			mIsProgressMonitorProgress = true;
		}
		
		private function assertProgressMonitorCompleted(aEvent : TaskEvent) : void
		{
			var progressMonitor : IProgressiveTask = IProgressiveTask(aEvent.target);
			
			assertTrue("ProgressMonitor should be progressed", mIsProgressMonitorProgress);
			assertEquals("mProgressMonitor.getProgress() should be equal to progressMonitor.getProgress()", 
				mProgressMonitor.getProgress(), 
				progressMonitor.getProgress());
				
			assertEquals("progress should be equal to 100", 100, mProgressMonitor.getProgress());
		}
		
		public function testAddTask() : void
		{
			var task1 : ITask = new FrameWaitingTask(1);
			var task2 : ITask = new WaitingTask(1);
			
			mProgressMonitor.addTask(task1);
			mProgressMonitor.addTask(task2);
			
			mProgressMonitor.addEventListener(ProgressiveTaskEvent.PROGRESS, onProgressMonitorProgress);
			mProgressMonitor.addEventListener(TaskEvent.COMPLETED, addAsync(assertProgressMonitorCompleted, 1100));
			
			mProgressMonitor.start();
			
			assertEquals("getProgress() should return 0", mProgressMonitor.getProgress(), 0);
			
			task1.start();
			task2.start();
		}
		
		public function testMonitorTasksContainer() : void
		{
			var taskSequence : TaskSequence = new TaskSequence();
			
			taskSequence.addTask(new FictiveTask());
			taskSequence.addTask(new FrameWaitingTask(1));
			taskSequence.addTask(new FictiveTask());
			taskSequence.addTask(new WaitingTask(0.1));
			
			mProgressMonitor.monitorTasksContainer(taskSequence);
			
			assertEquals("getProgress() should return 0", mProgressMonitor.getProgress(), 0);
			
			mProgressMonitor.addEventListener(ProgressiveTaskEvent.PROGRESS, onProgressMonitorProgress);
			mProgressMonitor.addEventListener(TaskEvent.COMPLETED, addAsync(assertProgressMonitorCompleted, 400));
			
			mProgressMonitor.start();
			
			taskSequence.start();			
		}
		
		public function testAddFixedPartItem() : void
		{
			var fictiveTask : FictiveTask = new FictiveTask();
			var fictiveTask30 : FictiveTask = new FictiveTask();
			
			mProgressMonitor.addFixedPartItem(fictiveTask30, 30);
			mProgressMonitor.addItem(fictiveTask);
			
			mProgressMonitor.addEventListener(ProgressiveTaskEvent.PROGRESS, addAsync(assertFixedPartItemProgress, 400));
			
			mProgressMonitor.start();

			fictiveTask30.start();
		}
		
		private function assertFixedPartItemProgress(aEvent : Event) : void
		{
			assertEquals("mProgressMonitor.getProgress should be 30%", mProgressMonitor.getProgress(), 30);
		}
		
		private var mTasksAdded : Boolean = false;
		public function testAddRemoveItemsDynamically() : void
		{
			var frameWaitingTask : FrameWaitingTask = new FrameWaitingTask(10);
			
			mProgressMonitor.addTask(frameWaitingTask);
			
			mProgressMonitor.addEventListener(ProgressiveTaskEvent.PROGRESS, onProgressMonitorProgress);
			mProgressMonitor.addEventListener(TaskEvent.COMPLETED, addAsync(assertTaskAdded, 1000));
			
			mProgressMonitor.start();
			
			frameWaitingTask.start();
			
			DoLaterUtil.doLater(addItemsAfterStart, [], 5);
		}
		
		private function assertTaskAdded(aEvent : Event) : void
		{
			assertTrue("Tasks should be added dynamically", mTasksAdded);
		}
		
		private function addItemsAfterStart() : void
		{
			mTasksAdded = true;
			
			var fictiveTask : FictiveTask = new FictiveTask();
			
			mProgressMonitor.addFixedPartTask(fictiveTask, 50);
			
			fictiveTask.start();
		}
	}
}